home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Trading on the Edge
/
Trading On The Edge - CD-ROM Toolkit (Wayzata Technology)(2031)(1994).bin
/
mac
/
Mac_Files
/
Software Utilities
/
NN PreProcessing
/
FINCMD.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-25
|
53KB
|
1,767 lines
/* 17:10 02-Jan-92 (fincmd.c) Command Line Parser */
#include <stdio.h>
#include <string.h>
#include "fincmd.h"
/************************************************************************
* Copyright(C) 1992 High-Tech Communications. *
* 103 Buckskin Court, Sewickley, PA 15143 *
* *
* Written by Casimir C. Klimasauskas *
* *
* All rights reserved. No part of this program may be reproduced, *
* stored in a retrieval system, or tramsmitted, in any form or by any *
* means, electronic, mechanical, photocopying, recording or otherwise *
* without the prior written permission of the copyright owner, *
* High-Tech Communications. *
* *
* These programs are supplied on an "as-is" basis with no warranties *
* of fitness or operability, either express or implied. *
* *
************************************************************************
*/
/************************************************************************
* *
* fincmd - Command Line Parser & Data Display Routines *
* *
************************************************************************
ParseLineI() Syntax:
? - prints out all of the current variables
?variable - prints out values associated with this variable
name? - prints out
a) syntax associated with name if unique
b) list of possible variables which match.
?? - prints out syntax of all variables
command - executes the command
variable value - assigns value to variable
variable=value - ditto
For Future:
actually set flag bits for items converted so if there are more
than one optional item, each individually can be accounted for.
*/
#ifdef LOCAL
#undef LOCAL
#endif
#ifdef TESTCMD
#define LOCAL
#else
#define LOCAL static
#endif
/* --- Special Local Defines --- */
#define TOKE_EOL 0 /* end of line */
#define TOKE_TRM 1 /* terminal character */
#define TOKE_STR 2 /* quoted string */
#define TOKE_CHR 3 /* single character (quoted) */
#define TOKE_INT 4 /* integer */
#define TOKE_FLT 5 /* floating point number */
#define TOKE_DBL 6 /* double precision number */
#define TOKE_LIT 7 /* literal */
#define COMMENT '!' /* start of comment character */
static long ConvertedL = {0}; /* # of items converted (kludge) */
/* */
/************************************************************************
* *
* Str2Str() - convert a character string to "C" format *
* *
************************************************************************
Escape sequences translated
\r, \n, \f, \b, \t, \', \", \\ - CR, LF, FF, BS, Tab, ', ", \
\xFF, \xF - hex character
\o, \oo, \ooo - octal character
^a..z, ^A..Z - control characters
^^ = ^
rc = Str2Str( dp, sp, fm )
dp - destination pointer (may be same as sp)
sp - source pointer
fm - format (0=translate escape chars)
rc = 0, all is well;
<> 0, error of some sort.
*/
LOCAL int Str2Str( dp, sp, fm ) /* convert "c" style string */
char *dp; /* destination pointer */
char *sp; /* source pointer */
int fm; /* format 0=translate escape chars */
{
FAST int rc; /* return code */
FAST int c; /* work character */
FAST int nc; /* # of chars */
FAST int wnc; /* work # of chars */
FAST int ac; /* alternate char */
FAST char *wsp; /* work string pointer */
rc = 0;
for( nc = 0; (c = *sp) != 0; sp++ ) {
if ( fm == 0 && c == '\\' ) { /* special escape chars */
wnc = 0;
wsp = sp;
ac = *++wsp;
c = 0;
if ( '0' <= ac && ac <= '7' ) {
/* --- octal literal --- */
for(; (ac = *wsp) != '\0' && wnc < 3; wsp++, wnc++ ) {
if ( '0' <= ac && ac <= '7' ) ac -= '0';
else break;
c = (c << 3) | ac;
}
goto CleanChar;
} else if ( ac == 'x' || ac == 'X' ) {
/* --- hex literal --- */
for( wsp++; (ac = *wsp) != '\0' && wnc < 2; wsp++, wnc++ ) {
if ( '0'<=ac && ac<='9' ) ac -= '0';
else if ( 'a'<=ac && ac<='f' ) ac -= 'a'-10;
else if ( 'A'<=ac && ac<='F' ) ac -= 'A'-10;
else break;
c = (c << 4) | ac;
}
CleanChar:
if ( wnc == 0 ) {
rc = -1; /* bad character */
c = *sp;
} else {
c &= 0xff;
sp = wsp-1;
}
} else {
/* --- single escape character --- */
switch( ac ) {
case '^': c = '^'; break; /* Caret */
case 'r': c = 0x0d; break; /* CR */
case 'n': c = 0x0a; break; /* LF */
case 'f': c = 0x0c; break; /* FF */
case 'b': c = 0x08; break; /* BS */
case 't': c = 0x09; break; /* tab */
case '\'': c = '\''; break; /* single quote */
case '\"': c = '\"'; break; /* double quote */
case '\\': c = '\\'; break; /* back-slash */
default: c = *sp; wsp = sp; rc = -1; break;
}
sp = wsp;
}
} else if ( fm == 0 && c == '^' ) {
wsp = sp;
ac = *++wsp; /* peek ahead one character */
wnc = 0; /* translation flag */
if ( 'A' <= ac && ac <= 'Z' ) {
c = ac - 'A' + 1; wnc++;
} else if ( 'a' <= ac && ac <= 'z' ) {
c = ac - 'a' + 1; wnc++;
} else if ( '^' == ac ) {
c = '^'; wnc++;
}
if ( wnc )
sp = wsp; /* valid translation */
}
*dp++ = c;
nc++;
}
*dp = '\0';
return( rc );
}
/* */
/************************************************************************
* *
* NextToke() - Get & Interpret next token in input buffer *
* *
************************************************************************
The buffer is parsed to see what follows. It returns one of the
following return types and updates the buffer pointer to the next
non-blank character past it.
TOKE_EOL - at end of line
TOKE_TRM (CV_TokeLong)
terminator character !, <null> or terminator character
TOKE_STR (CV_TokeString)
string "...." (when stored, 1st char is length)
or "...""..." (embedded quote)
all characters accepted except <CR> & <LF>.
"C" style escape sequences are converted.
TOKE_CHR (CV_TokeLong & CV_TokeChar)
character 'c' (quoted character)
must be >= ' ', or use \r, \n, \f, \b, \t,
\xFF, \ooo, \\, \'.
TOKE_INT (CV_TokeLong)
decimal integer [+/-][1..9][d...] d: 0..9
octal integer [+/-]0[d...] d: 0..7
hex integer [+/-]0x[d...] d: 0..9, a..f, A..F
binary integer [+/-]0b[d...] d: 0..1
TOKE_FLT (CV_TokeDBL)
float [+/-][d...].[d..][E+/-d[..]]
TOKE_DBL (CV_TokeDBL)
double [+/-][d...].[d..][D+/-d[..]]
(default is "float" )
TOKE_LIT (CV_TokeToke)
token anything else.
*/
LOCAL long CV_TokeLong = {0}; /* CV_Token as "long" */
LOCAL double CV_TokeDBL = {0.}; /* CV_Token as "double" */
LOCAL char CV_TokeString[132] = {0}; /* CV_Token as "string" */
LOCAL char CV_TokeToke[132] = {0}; /* CV_Token as literal string */
LOCAL int NextToke( spp, TermsP, tp ) /* get next token */
char **spp; /* pointer to pointer to input string */
char *TermsP; /* terminals */
int *tp; /* pointer to return pointer */
{
FAST int rc; /* return code */
FAST long base; /* current "base" */
FAST int c, cn; /* char, "numeric" character */
FAST int decpt; /* decimal points */
FAST int exp; /* exponent */
FAST int sign, esign; /* sign of item, exponent sign */
FAST int gotdig; /* got a digit */
FAST char *sp; /* work string pointer */
FAST char *dp; /* destination pointer */
FAST char *sp0; /* initial string pointer */
FAST char *spToke; /* token end of string pointer */
FAST char *wsp; /* work string pointer */
FAST int aexp; /* absolute exponent */
FAST double wD; /* work value */
char CV_TokeChar[8]; /* CV_Token as "char" work area */
char TermsCA[68]; /* local "terminators" */
/* --- initialize work variables --- */
memset( TermsCA, 0, sizeof(TermsCA) );
TermsCA[0] = COMMENT;
if ( TermsP )
strncpy( &TermsCA[1], TermsP, sizeof(TermsCA)-2 );
CV_TokeString[0] = 0;
CV_TokeString[1] = 0;
CV_TokeLong = 0;
CV_TokeDBL = 0.0;
memset( (char *)CV_TokeToke, 0, sizeof(CV_TokeToke) );
sp = *spp;
while( *sp && *sp <= ' ' ) sp++; /* skip leading spaces */
/* --- Check for end of line --- */
if ( *sp == 0 ) {
rc = TOKE_EOL; /* end of line */
goto Done;
}
sp0 = sp; /* first non-blank character */
/* --- Check for "terminator" --- */
if ( strchr(TermsCA,*sp) != (char *)0 ) {
rc = TOKE_TRM; /* terminator */
CV_TokeLong = *sp & 0xff; /* stay positioned there */
goto Done;
}
/* --- set up token, regardless --- */
wsp = &CV_TokeToke[1];
for( cn = 1; (c = *sp) > ' ' && strchr(TermsCA,c)==(char *)0; sp++ ) {
if ( cn < sizeof(CV_TokeToke)-1 )
*wsp++ = c; /* stuff next char */
cn++;
}
*wsp = 0;
cn--;
CV_TokeToke[0] = cn;
spToke = sp; /* save string for return */
/* --- try for quoted string --- */
sp = sp0;
rc = TOKE_STR; /* quoted string */
wsp = &CV_TokeString[1];
if ( *sp == '"' ) {
sp++;
for( cn = 0; (c = *sp) != 0; sp++, cn++ ) {
if ( c == '\r' || c == '\n' )
break; /* bad string */
if ( c == '"' ) { /* end of string ? */
if ( sp[1] > ' ' && sp[1] != '"' )
break; /* bad string */
if ( sp[1] <= ' ' ) { /* end of string */
/* --- map escape sequences --- */
*wsp = 0; /* null terminate string */
Str2Str( &CV_TokeString[1], &CV_TokeString[1], 0 );
CV_TokeString[0] = strlen( &CV_TokeString[1] );
sp++;
goto Done;
}
}
if ( cn < sizeof(CV_TokeString)-3 )
*wsp++ = c;
if ( c == '"' )
sp++; /* skip double quote */
}
}
CV_TokeString[0] = 0;
/* --- try for quoted character --- */
sp = sp0;
rc = TOKE_CHR; /* quoted character */
memset( CV_TokeChar, 0, sizeof(CV_TokeChar) );
if ( *sp == '\'' ) {
for( cn = 0, sp++; (c = *sp) != '\0'; sp++ ) {
if ( c < ' ' || cn >= sizeof( CV_TokeChar )-2 )
break; /* illegal */
if ( c == '\'' ) {
if ( cn == 0 ) break; /* illegal */
if ( CV_TokeChar[cn-1] != '\\' ) {
/* --- hit end of string: check for validity --- */
if ( Str2Str( &CV_TokeChar[0], &CV_TokeChar[0], 0 ) )
break; /* illegal somehow */
if ( CV_TokeChar[1] != 0 )
break; /* multi-char string */
CV_TokeLong = CV_TokeChar[0] & 0xff; /* force unsigned */
sp++;
goto Done;
}
}
CV_TokeChar[cn++] = c;
CV_TokeChar[cn] = 0;
}
}
/* --- see if we have a "long" --- */
sp = sp0; /* reset pointer */
rc = TOKE_INT; /* assume integer token */
base = 10; /* default base */
sign = 0; /* no leading sign */
CV_TokeLong = 0; /* token as long */
c = *sp;
if ( c == '+' || c == '-' ) { /* take care of leading sign */
sign = (c == '+'? 1:-1);
c = *++sp;
}
if ( c == '0' ) { /* leading zero special cases */
base = 8;
if ( sp[1] == 'x' || sp[1] == 'X' ) {
base = 16;
sp += 2;
} else if ( sp[1] == 'b' || sp[1] == 'B' ) {
base = 2;
sp += 2;
} else sp++;
}
for( ; (c = *sp) > ' ' && strchr(TermsCA,c)==(char *)0; sp++ ) {
if ( '0' <= c && c <= '9' ) cn = c - '0';
else if ( 'a' <= c && c <= 'f' ) cn = c - 'a' + 10;
else if ( 'A' <= c && c <= 'F' ) cn = c - 'A' + 10;
else cn = -1;
if ( cn < 0 || base <= cn ) {
rc = 0;
break;
}
CV_TokeLong = (base * CV_TokeLong) + cn;
}
if ( (*sp <= ' ' || strchr(TermsCA,*sp) != (char *)0) && rc != 0 ) {
if ( sign < 0 ) CV_TokeLong = 0 - CV_TokeLong;
goto Done; /* it is LONG !!! */
}
CV_TokeLong = 0;
/* --- not long, try float or double --- */
rc = TOKE_FLT; /* assume double */
sp = sp0; /* reset pointer */
sign = 0; /* no sign */
CV_TokeDBL = 0.0; /* token as double */
esign = 0; /* no exponent sign */
exp = 0; /* exponent value */
decpt = -1; /* no decimal point */
gotdig = 0; /* got a digit */
c = *sp; /* first character */
if ( c == '+' || c == '-' ) {
sign = (c == '+'? 1:-1);
c = *++sp;
}
for( ; (c = *sp) > ' '; sp++ ) {
if ( c == '.' ) {
if ( decpt >= 0 ) {
NotDbl:
rc = 0;
break;
}
decpt = 0;
} else if ( '0' <= c && c <= '9' ) {
cn = c - '0';
CV_TokeDBL = (CV_TokeDBL * 10.) + (double)(cn);
if ( decpt >= 0 ) decpt++;
gotdig++;
} else if ( c == 'd' || c == 'D' || c == 'e' || c == 'E' ) {
/* exponent */
if ( gotdig == 0 )
goto NotDbl;
rc = (c == 'd' || c == 'D' )? TOKE_DBL:TOKE_FLT;
c = *++sp;
if ( c == '+' || c == '-' ) {
esign = (c == '+'? 1:-1);
sp++;
}
while( '0' <= *sp && *sp <= '9' ) {
exp = (10 * exp) + (*sp - '0');
sp++;
}
if ( esign < 0 ) exp = 0 - exp;
break;
} else {
goto NotDbl; /* bad character */
}
}
if ( (*sp <= ' ' || strchr(TermsCA,*sp) != (char *)0) && rc != 0 ) {
if ( decpt > 0 )
exp -= decpt;
/* --- Special conversion to minimize rounding errors --- */
aexp = (exp >= 0? exp:(-exp));
wD = 1.0;
if ( aexp > 40 ) aexp = 40;
while( aexp > 5 ) { wD *= 100000.; aexp -= 5; } /* no rounding */
while( aexp > 0 ) { wD *= 10.; aexp -= 1; } /* no rounding */
if ( exp > 0 ) { CV_TokeDBL *= wD; }
else if ( exp < 0 ) { CV_TokeDBL /= wD; }
if ( sign < 0 ) CV_TokeDBL = 0. - CV_TokeDBL;
goto Done; /* it is FLOAT !!! */
}
CV_TokeDBL = 0.0;
/* --- must be a regular token --- */
rc = TOKE_LIT;
sp = spToke;
Done:
while( *sp && *sp <= ' ' ) sp++; /* skip trailing spaces */
*spp = sp;
if ( tp ) *tp = rc;
return( rc );
}
/* */
/************************************************************************
* *
* SearchLitTableP() - Search literal table *
* *
************************************************************************
Searches literal table until string is found or end of table.
If end of table is reached, NULL (fail) is returned.
*/
LOCAL LIT *SearchLitTableP( msP, LitTabP ) /* search literal table */
char *msP; /* string to search for */
LIT *LitTabP; /* command table pointer */
{
FAST int ca, cb; /* compare characters */
FAST char *sP; /* work char pointer */
FAST char *aP; /* alt work character */
FAST LIT *litP; /* work command pointer */
FAST int nlI; /* near literal counter */
FAST LIT *nlP; /* near literal pointer */
if ( LitTabP == (LIT *)0 || msP == (char *)0 )
goto Fail;
for( sP = msP; (ca = *sP) != 0; sP++ ) /* convert to lower case */
if ( 'A' <= ca && ca <= 'Z' ) *sP = ca - ('A'-'a');
nlP = (LIT *)0;
nlI = 0;
for( litP = LitTabP; (aP = litP->LNameCP) != (char *)0; litP++ ) {
for( sP = msP;; sP++, aP++) {
ca = *sP;
cb = *aP;
if ( ca == 0 ) {
if ( cb == 0 ) return( litP ); /* exact match */
nlI++; /* count "near" match */
nlP = litP; /* save ptr to last */
break;
}
if ( ca != cb ) {
if ( 'A' <= cb && cb <= 'Z' ) {
cb -= 'A' - 'a';
if ( ca != cb ) break;
} else break;
}
}
}
if ( nlI == 1 ) return( nlP ); /* near & unique */
Fail:
return( (LIT *)0 );
}
/* */
/************************************************************************
* *
* SearchCmdTableP() - Search command table *
* *
************************************************************************
Searches command table until string is found or end of table
(null string pointer) is reached.
returns pointer into command table or NULL (fail).
*/
LOCAL CMD *SearchCmdTableP( msP, CmdTabP, ModeI ) /* search command table */
char *msP; /* string to search for */
CMD *CmdTabP; /* command table pointer */
int ModeI; /* =0, exact; =1, partial */
{
FAST int ca, cb; /* compare characters */
FAST char *sP; /* work char pointer */
FAST char *aP; /* alt work character */
FAST CMD *cmdP; /* work command pointer */
FAST CMD *nlP; /* near match */
FAST int nlI; /* counter for near match */
if ( CmdTabP == (CMD *)0 || msP == (char *)0 )
goto Fail;
for( sP = msP; (ca = *sP) != 0; sP++ ) /* convert to lower case */
if ( 'A' <= ca && ca <= 'Z' ) *sP = ca - ('A'-'a');
nlI = 0;
nlP = (CMD *)0;
for( cmdP = CmdTabP; (aP = cmdP->CNameCP) != (char *)0; cmdP++ ) {
for( sP = msP;; sP++, aP++) {
ca = *sP;
cb = *aP;
if ( ca == 0 ) {
if ( cb == 0 || ModeI )
return( cmdP ); /* exact match or partial request */
nlI++; /* count near hits */
nlP = cmdP; /* save pointer to last */
break;
}
if ( ca != cb ) {
if ( 'A' <= cb && cb <= 'Z' ) {
cb -= 'A' - 'a'; /* try case insensitive */
if ( ca != cb ) break;
} else break;
}
}
}
if ( nlI == 1 ) return( nlP ); /* one "near" match */
Fail:
return( (CMD *)0 );
}
/* */
/************************************************************************
* *
* StoreValueI() - store a value into a data element *
* *
************************************************************************
rc = 0: all is well; else, error & message printed.
*/
int StoreValueI( cP, inP, dV ) /* store a value */
FAST char *cP; /* data pointer (this item) */
FAST INPUT *inP; /* input structure */
FAST double dV; /* value to store */
{
FAST UVP p; /* universal pointer */
FAST int SizeI; /* size of item */
FAST long vL; /* work long */
FAST int TypeI; /* type of item */
char buf[80]; /* message buffer */
if ( inP == (INPUT *)0 )
return( -1 );
if ( cP == (char *)0 ) cP = (char *)inP->IValP;
if ( (p.cP = cP) == (char *)0 || (SizeI = inP->ISizeI) == 0 ) {
Fail:
sprintf( buf, "** Store Failure ptr=%08lx size=%d func i=0x%02x\n",
p.cP, SizeI, inP->IInFuncC & 0xff );
MsgER( buf );
return( -1 );
}
TypeI = (inP->IInFuncC & IO_MASK);
if ( TypeI == IO_FLT ) {
/* --- NOTE: on some systems (transputers)
* sizeof(float) == sizeof(double)
*/
if ( SizeI == sizeof(float) ) *p.fP = dV;
else if ( SizeI == sizeof(double) ) *p.dP = dV;
else goto Fail;
} else if ( TypeI == IO_INT || TypeI == IO_BIT ) {
if ( dV < -((double)0x7fffffffL) ) vL = 0x80000000L;
else if ( dV > ((double)0x7fffffffL) ) vL = 0x7fffffffL;
else vL = (dV < 0.0? (dV - 0.5):(dV + 0.5));
switch( SizeI ) {
case sizeof(char): *p.cP = vL; break;
case sizeof(short): *p.sP = vL; break;
case sizeof(long): *p.lP = vL; break;
default: goto Fail;
}
} else goto Fail;
return( 0 );
}
/* */
/************************************************************************
* *
* ParseBitsI() - Parse the "or" of several bit masks *
* *
************************************************************************
start with the first element in the list.
Try looking it up in the literal table or converting it.
NOTE: This makes the assumption that a literal has been detected,
and it did not match something in the table. So, this will
attempt to break it into a series of smaller units which are
merged together as "bits".
*/
LOCAL int ParseBitsI( sPP, inP, lP ) /* parse merge bit field */
char **sPP; /* pointer to return string */
INPUT *inP; /* input control block */
long *lP; /* result pointer */
{
char *wsP; /* work string pointer */
char *psP; /* pre-token string pointer */
FAST long wL; /* "merge" bits */
FAST long vL; /* temp to convert literal tables */
FAST int rcI; /* return code */
FAST int lcI; /* last character */
FAST LIT *litP; /* literal pointer */
vL = 0;
wsP = psP = *sPP; /* buffer pointer */
lcI = 0;
for(;;) {
rcI = NextToke( &wsP, "|,", (int *)0 ) ; /* next token */
switch( rcI ) {
case TOKE_EOL:
case TOKE_TRM:
if ( lcI == 0 && CV_TokeLong != '|' )
goto Good;
case TOKE_STR:
goto Error;
case TOKE_LIT:
if ( (litP = SearchLitTableP( &CV_TokeToke[1], inP->ILitTabP )) == (LIT *)0 )
goto Error;
wL = litP->LValueD;
vL |= wL;
break;
case TOKE_FLT: /* float */
case TOKE_DBL: /* double */
wL = (CV_TokeDBL < 0.0? (CV_TokeDBL-0.5):(CV_TokeDBL+0.5));
goto IntCom;
case TOKE_CHR: /* quoted character */
case TOKE_INT: /* integer */
wL = CV_TokeLong;
IntCom:
if ( (inP->IInFuncC & IO_LITONLY) != 0 )
goto Error;
vL |= wL; /* merge in new bits */
break;
}
psP = wsP;
if ( *wsP == '|' ) { /* valid data, see if more */
wsP++;
lcI = '|';
} else lcI = 0;
}
Good:
*lP = vL;
*sPP = wsP;
return( 0 );
Error:
*sPP = psP;
return( -1 );
}
/* */
/************************************************************************
* *
* ParseStrI() - Parse a string or file name *
* *
************************************************************************
Only looks for one of them. If the string or file name
decodes like a valid floating point number or double,
this is an error.
*/
LOCAL int ParseStrI( sPP, inP, SCI, InMI ) /* parse a string or file name */
char **sPP; /* pointer to buffer pointer */
INPUT *inP; /* input data block */
int SCI; /* =1, syntax check */
int InMI; /* in mode: IO_FNM, IO_FLD, IO_DTE or IO_STR */
{
char *wsP; /* work string pointer */
FAST char *asP; /* work string pointer */
FAST char *cP; /* data pointer */
FAST char *sP; /* string pointer */
FAST int lenI; /* length of string (max) */
FAST int rcI; /* internal return code */
FAST int cI; /* character */
if ( inP == (INPUT *)0 || (cP = inP->IValP) == (char *)0 )
return( 0 ); /* bad data pointer */
if ( sPP == (char **)0 || (wsP = *sPP) == (char *)0 )
return( 0 ); /* bad buffer pointer */
lenI = inP->ISizeI & 0xff; /* size of string */
rcI = NextToke( &wsP, ",", (int *)0 );
switch( rcI ) {
case TOKE_EOL:
case TOKE_TRM:
if ( (inP->IInFuncC & IO_OPT) == 0 )
goto Error;
if ( CV_TokeLong == ',' ) /* skip this one */
wsP++; /* skip the terminal too */
break;
case TOKE_FLT:
case TOKE_DBL:
case TOKE_INT:
default:
goto Error;
case TOKE_CHR: /* quoted character */
if ( InMI == IO_FNM || InMI == IO_FLD || InMI == IO_DTE )
goto Error; /* invalid file */
if ( !SCI ) {
*cP++ = CV_TokeLong;
*cP++ = 0;
}
goto GotVal;
case TOKE_LIT: sP = &CV_TokeToke[1]; goto TokeStore;
case TOKE_STR: sP = &CV_TokeString[1];
TokeStore:
switch( InMI ) {
case IO_FNM: /* --- File name, do minimal syntax check --- */
for( asP = sP; (cI = *asP) != 0; asP++ ) {
if ( !( ('0' <= cI && cI <= '9') ||
('a' <= cI && cI <= 'z') ||
('A' <= cI && cI <= 'Z') ||
'.' == cI || '_' == cI || ':' == cI ||
'/' == cI || '\\' == cI ) )
goto Error; /* invalid file name */
}
break;
case IO_FLD: /* --- Field reference, do syntax check --- */
rcI = 0; /* state variable */
for( asP = sP; (cI = *asP) != 0; asP++ ) {
switch( cI ) {
case '.': /* field-label separator */
if ( rcI || asP == sP ) goto Error;
rcI = 1;
break;
case '(':
case '[': /* start of offset */
if ( rcI >= 2 ) goto Error;
rcI = 2;
if ( asP[1] == '+' | asP[1] == '-' ) asP++;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if ( rcI == 2 ) rcI = 3;
if ( rcI > 3 ) goto Error;
break;
case ')':
case ']': /* end of offset */
if ( rcI < 3 ) goto Error;
rcI = 4;
break;
default:
if ( rcI > 1 ) goto Error;
if ( !( ('a' <= cI && cI <= 'z') ||
('A' <= cI && cI <= 'Z') ||
cI == '/' || cI == '_' ) )
goto Error;
}
}
break;
case IO_DTE: /* syntax check on date */
rcI = 0;
for( asP = sP; (cI = *asP) != 0; asP++ ) {
switch( cI ) {
case '-': /* field separator */
case '/':
if ( rcI == 0 && asP == sP ) goto Error;
if ( asP[-1] == '-' || asP[-1] == '/' )
goto Error;
if ( rcI >= 2 ) goto Error;
rcI++;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
break;
default:
goto Error;
}
}
if ( rcI != 2 ) goto Error;
break;
}
if ( !SCI ) {
strncpy( cP, sP, lenI );
cP[lenI-1] = 0;
}
GotVal:
ConvertedL++;
if ( *wsP == ',' )
wsP++; /* skip separator */
break;
}
*sPP = wsP; /* position after token */
return( 0 );
Error:
return( -1 );
}
/* */
/************************************************************************
* *
* ParseValI() - Parse an integer, long, or float or array of them *
* *
************************************************************************
Looks for: value,value,value
or: value value value, value
(accepts commas or spaces or mixed as delimiters)
value is: 'c' - quoted character
int - decimal, hex, octal, or binary integer
flt - floating point number
lit - literal with a numeric translation
*/
LOCAL int ParseValI( sPP, inP, SCI ) /* parse an integer */
char **sPP; /* pointer to char string */
INPUT *inP; /* current command table entry */
int SCI; /* =1, syntax check */
{
char *wsP; /* work string pointer */
char *psP; /* pre-token position */
FAST int rcI; /* return code */
FAST int vctrI; /* variable counter */
FAST int vctr0I; /* initial variable counter */
FAST char *cP; /* data pointer */
FAST long vL; /* work long */
FAST double vD; /* work double */
FAST LIT *litP; /* literal table pointer */
FAST int ValTypeI; /* value type */
long wL; /* work long */
if ( inP == (INPUT *)0 || (cP = inP->IValP) == (char *)0 )
return( 0 ); /* bad data pointer */
if ( sPP == (char **)0 || (wsP = *sPP) == (char *)0 )
return( 0 ); /* bad buffer pointer */
vctr0I = inP->IItemsI & 0xff; /* # of items */
vctr0I = (vctr0I < 1)? 1:vctr0I; /* at least one item */
ValTypeI = (inP->IInFuncC & IO_MASK); /* type of conversion */
for( vctrI = vctr0I; vctrI > 0; vctrI--) {
psP = wsP;
rcI = NextToke( &wsP, ",", (int *)0 );
switch( rcI ) {
case TOKE_EOL: /* EOL or terminal */
case TOKE_TRM:
if ( (inP->IInFuncC & IO_OPT) == 0 )
goto Error; /* not optional */
if ( CV_TokeLong == ',' ) {
wsP++; /* skip the terminal */
cP += inP->ISizeI&0xff; /* skip this item */
break;
}
goto Good; /* done with line */
case TOKE_STR: /* strings don't work */
goto Error;
case TOKE_LIT: /* look up literal in table */
litP = SearchLitTableP( &CV_TokeToke[1], inP->ILitTabP );
if ( litP == (LIT *)0 ) {
/* --- if "IO_BIT", we may have a complex construct --- */
if ( ValTypeI == IO_BIT ) {
if ( ParseBitsI( &psP, inP, &wL ) != 0 )
goto Error;
vL = wL; /* successful "bit-parse" */
vD = vL;
} else goto Error;
} else {
vD = litP->LValueD;
vL = vD;
}
goto StoreToke2;
case TOKE_FLT: /* float, make it long */
case TOKE_DBL:
vD = CV_TokeDBL;
vL = vD;
goto StoreToke;
case TOKE_CHR: /* char or int, use it */
case TOKE_INT:
vL = CV_TokeLong;
vD = vL;
StoreToke:
if ( ValTypeI != IO_FLT ) {
/* --- round integers --- */
vL = (vD < 0.0? (vD - 0.5):(vD + 0.5));
vD = vL; /* store as integer */
}
if ( (inP->IInFuncC & IO_LITONLY) != 0 &&
(litP = inP->ILitTabP) != (LIT *)0 ) {
/* --- Check to see it is in literal table --- */
for( ; litP->LNameCP != (char *)0; litP++ )
if ( vD == litP->LValueD )
goto StoreToke2; /* found in table, store it */
goto Error; /* not in table ! */
}
StoreToke2: /* passed literal test */
ConvertedL++;
if ( !SCI ) /* syntax check only */
StoreValueI( cP, inP, vD );
cP += inP->ISizeI & 0xff;
if ( *wsP == ',' )
wsP++; /* skip optional comma */
break;
}
}
Good:
*sPP = wsP; /* position after token */
return( 0 );
Error:
*sPP = psP; /* position prior to error */
return( -1 );
}
/* */
/************************************************************************
* *
* ParseLstI() - Parse an assignment list *
* *
************************************************************************
This routine takes a list of variables to parse and
parses each of them in turn until the end of list is reached.
When using commas, a value can be left alone by a "double" comma.
inP->IValP points to the list of input items
The last item has a null data pointer
*/
LOCAL int ParseLstI( sPP, inP, SCI ) /* parse a command list */
char **sPP; /* pointer to buffer pointer */
INPUT *inP; /* input list pointer */
int SCI; /* =1, syntax check only */
{
FAST INPUT *ainP; /* alternate input list */
char *wsP; /* work character pointer */
FAST int rcI; /* local return code */
FAST int wtI; /* work type */
if ( inP == (INPUT *)0 || (ainP = (INPUT *)inP->IValP) == (INPUT *)0 )
return( -1 ); /* bad call */
if ( sPP == (char **)0 || (wsP = *sPP) == (char *)0 )
return( 0 ); /* bad buffer pointer */
rcI = 0;
for( ; ainP->IValP != (char *)0; ainP++ ) {
/* --- Parse the following values as required --- */
switch( (wtI = ainP->IInFuncC & IO_MASK) ) {
case IO_NAK: default: rcI = 0; break;
case IO_BIT:
case IO_INT: case IO_FLT: rcI = ParseValI( &wsP, ainP, SCI ); break;
case IO_STR: case IO_FNM:
case IO_DTE: case IO_FLD: rcI = ParseStrI( &wsP, ainP, SCI, wtI ); break;
case IO_LST: rcI = ParseLstI( &wsP, ainP, SCI ); break;
}
if ( rcI < 0 )
break;
}
*sPP = wsP;
return( rcI );
}
/* */
/************************************************************************
* *
* ParseLineI() - Parse a Line & perform any tasks required *
* *
************************************************************************
rc = -1, error in parsing
rc = 0, all is well, nothing to do
rc = 1, executed successfully
Procedure:
1) Parse the input string & get a literal token.
2) Search the command table for the literal.
- Not found: error
3) Execute the "input routine" if any.
- rc <> 0, error
4) Check for "eol"
- not there, error.
5) Execute the "action routine" if any.
- rc <> 0, error
6) done.
*/
int ParseLineI( sPP, CmdTabP, ErrFP, SCI ) /* parse a line */
char **sPP; /* character string pointer */
CMD *CmdTabP; /* command table */
FILE *ErrFP; /* file handle for errors */
int SCI; /* =1, perform syntax check only */
{
char *wsP; /* work string pointer */
FAST char *asP; /* alt string pointer */
FAST int rcI; /* work return code */
FAST int wtI; /* work type */
FAST CMD *cmdP; /* work command pointer */
FAST INPUT *inP; /* i/o block pointer */
FAST int HelpI; /* user needs help in terms of commands */
FAST char *PrefixP; /* prefix */
char buf[80]; /* message buffer */
if ( CmdTabP == (CMD *)0 ||
sPP == (char **)0 || (wsP = *sPP) == (char *)0 )
goto Ok; /* nothing to do */
if ( ErrFP == (FILE *)0 )
ErrFP = stderr;
/* --- Check to see if we are reading "lotus" format --- */
if ( *wsP == '"' ) {
/* --- Lotus format line, "fix" it up --- */
asP = wsP;
*asP++ = ' '; /* replace leading quote */
if ( strncmp( asP, "PARM", 4 ) == 0 ) {
*--asP = '!'; /* make it a "comment" line */
goto Ok; /* nothing to do ! */
}
while( *asP && *asP != '"' ) asP++;
if ( *asP ) {
*asP++ = ' ' ; /* kill trailing quote */
if ( *asP == ',' ) *asP++ = ' '; /* comma */
if ( *asP == '"' ) *asP++ = ' '; /* next quote */
while( *asP && *asP != '"' ) asP++;
if ( *asP ) {
*asP++ = ' '; /* kill final quote */
if ( *asP == ',' ) *asP++ = ' '; /* comma */
if ( *asP == '"' ) *asP++ = ' '; /* next quote */
}
}
}
/* --- Find the command in the command table --- */
PrefixP = (ErrFP == stdout? "":"=P= ");
asP = wsP; /* save for syntax error */
HelpI = 0;
rcI = NextToke( &wsP, "=?", (int *)0 ); /* get next token */
if ( *wsP == '?' ) HelpI = 1;
switch( rcI ) {
case TOKE_TRM:
if ( CV_TokeLong == '=' ) goto Syntax;
asP = wsP;
if ( HelpI ) {
wsP++;
asP = wsP;
rcI = NextToke( &wsP, "?", (int *)0 ); /* get next token */
switch( rcI ) {
case TOKE_EOL: case TOKE_TRM:
if ( CV_TokeLong == '?' )
PrintTableI( CmdTabP, ErrFP, PrefixP, -1 );
else PrintTableI( CmdTabP, ErrFP, PrefixP, 0 );
break;
case TOKE_LIT:
if ( (cmdP = SearchCmdTableP( &CV_TokeToke[1], CmdTabP, 0 )) != (CMD *)0 ) {
/* --- Single unique item --- */
PrintTableItemI( cmdP, ErrFP, PrefixP, 0 );
break;
}
for( wtI = 0, cmdP = CmdTabP; ; cmdP++ ) {
/* --- ambiguous item --- */
if ( (cmdP = SearchCmdTableP( &CV_TokeToke[1], cmdP, 1)) == (CMD *)0 )
break;
wtI++;
PrintTableItemI( cmdP, ErrFP, PrefixP, 0 );
}
if ( wtI == 0 ) goto Syntax;
default:
break;
}
rcI = -1;
goto Exit;
}
case TOKE_EOL:
goto Ok; /* nothing to do */
case TOKE_LIT: break; /* command to process */
default: goto Syntax; /* error */
}
/* --- If help is requested, print out all "ambiguous" commands --- */
cmdP = SearchCmdTableP( &CV_TokeToke[1], CmdTabP, 0 );
if ( HelpI ) {
if ( cmdP ) { /* print out options associated with this command */
PrintTableItemI( cmdP, ErrFP, (char *)0, -1 );
} else { /* print out commands which match */
for( wtI = 0, cmdP = CmdTabP; ; cmdP++ ) {
if ( (cmdP = SearchCmdTableP( &CV_TokeToke[1], cmdP, 1)) == (CMD *)0 )
break;
wtI++;
fprintf( ErrFP, "%s%s\n", PrefixP, cmdP->CNameCP );
}
if ( wtI == 0 ) goto Syntax;
}
fflush( ErrFP );
rcI = -1;
goto Exit;
}
/* --- Search Command Table for match --- */
if ( cmdP == (CMD *)0 ) {
wsP = asP; /* point to token */
goto Syntax;
}
if ( (!cmdP->CActRtnP || (cmdP->CInS.IInFuncC & IO_DSP) != 0 )
&& *wsP == '=' ) {
/* --- assignment statement, kill optional "=" sign --- */
wsP++;
while( *wsP && *wsP <= ' ' ) wsP++;
}
/* --- Parse variables as required --- */
ConvertedL = 0; /* nothing converted yet */
inP = &cmdP->CInS;
switch( (wtI = inP->IInFuncC & IO_MASK) ) {
case IO_NAK: default: rcI = 0; break;
case IO_BIT:
case IO_INT: case IO_FLT: rcI = ParseValI( &wsP, inP, SCI ); break;
case IO_STR: case IO_FNM:
case IO_DTE: case IO_FLD: rcI = ParseStrI( &wsP, inP, SCI, wtI ); break;
case IO_LST: rcI = ParseLstI( &wsP, inP, SCI ); break;
}
if ( rcI != 0 ) goto Syntax;
/* --- Check for end of line --- */
if ( *wsP != COMMENT && *wsP != '\0' )
goto Syntax;
/* --- Perform any "post" action routine required --- */
if ( cmdP->CActRtnP ) {
if ( SCI ) rcI = 0;
else rcI = (cmdP->CActRtnP)( cmdP, ConvertedL, ErrFP );
if ( rcI != 0 ) {
sprintf( buf, "Action routine for command <%s> failed rc=%d\n",
cmdP->CNameCP, rcI );
MsgER( buf );
goto Exit;
}
} else if ( ConvertedL == 0 ) {
/* --- Assignment MUST have a converted item --- */
goto Syntax;
}
Exit:
#ifdef TESTCMD
printf( "rcI = %d, ConvertedL = %ld\n", rcI, ConvertedL );
#endif
*sPP = wsP;
return( rcI );
Ok:
rcI = 0;
goto Exit;
Syntax:
/* --- Clean up the string --- */
for( asP = *sPP; *asP != 0; asP++ ) {
if ( *asP == '\r' || *asP == '\n' ) *asP = 0;
else if ( *asP < ' ' ) *asP = ' ';
}
/* --- Put a ^ under where the error occurred --- */
fputs( *sPP, ErrFP ); /* write the line */
fputs( "\n", ErrFP );
for( asP = *sPP; asP < wsP; asP++ )
fputs( " ", ErrFP ); /* space over */
fputs( "^ Syntax Error\n", ErrFP ); /* show where error is */
return( -1 );
}
/* */
/************************************************************************
* *
* PrintBitI() - Expand out & print a bit-field *
* *
************************************************************************
NOTE: This routine should be called ONLY WHEN:
1) a literal table exists.
2) the value to decode is NON-zero
3) the data format is IO_BIT.
*/
static char *FmtA[] = /* formats */
{ "%ld", "%lu", "0x%lx", "0%lo", "%.0f", "%.1f", "%.2f", "%.3f", "%.4f", "%.5f" };
LOCAL int PrintBitI( vL, inP, OutFP ) /* expand & print a bit-field */
FAST long vL; /* value to expand */
FAST INPUT *inP; /* literal table pointer */
FAST FILE *OutFP; /* output file pointer */
{
FAST LIT *litP; /* literal pointer */
FAST long wL; /* work long */
litP = inP->ILitTabP;
for( ; litP->LNameCP != 0; litP++ ) {
if ( (wL = litP->LValueD) != 0 ) {
if ( (vL & wL) == wL ) {
fputs( litP->LNameCP, OutFP );
vL &= ~wL;
if ( vL == 0 ) break;
fputs( "|", OutFP );
}
}
}
if ( vL != 0 )
fprintf( OutFP, FmtA[inP->IOutFuncC], vL );
return( 0 );
}
/* */
/************************************************************************
* *
* PrintValI() - Print out a data value *
* *
************************************************************************
*/
LOCAL int PrintValI( inP, OutFP, IPI ) /* print out a data value */
FAST INPUT *inP; /* input list pointer */
FAST FILE *OutFP; /* output file pointer */
FAST int IPI; /* =1, lotus import format */
{
FAST UVP p; /* universal pointer */
FAST long vL; /* long value */
FAST long UsgnL; /* "unsigned mask" */
FAST long SBitL; /* sign bit */
FAST double vD; /* double value */
FAST int ctrI; /* work counter */
FAST int wxI; /* work index */
FAST LIT *litP; /* literal table pointer */
FAST int lIPI; /* local IPI */
FAST int ValTypeI; /* value type */
FAST int exI; /* end index */
FAST int typeI; /* type index */
FAST char *sP; /* string pointer */
if ( inP == (INPUT *)0 || (p.cP = inP->IValP) == (char *)0 )
return( 0 );
if ( OutFP == (FILE *)0 )
OutFP = stdout;
ctrI = inP->IItemsI & 0xff;
ctrI = (ctrI < 1? 1:ctrI);
if ( IPI < 0 ) {
/* --- Print out syntax for this item --- */
exI = inP->IInFuncC;
typeI = exI & IO_MASK;
litP = inP->ILitTabP;
if ( ConvertedL ) fputs( ",", OutFP );
ConvertedL++;
if ( (exI & IO_OPT) != 0 ) fputs( "[", OutFP );
if ( typeI == IO_STR ) fputs( "STRING", OutFP );
else if ( typeI == IO_FNM ) fputs( "FILE", OutFP );
else if ( typeI == IO_FLD ) fputs( "REF.LAB[+/-OFF]", OutFP );
else if ( typeI == IO_DTE ) fputs( "MM/DD/YY", OutFP );
else {
if ( ctrI > 1 ) fputs( "LIST:", OutFP );
if ( inP->ILitTabP != (LIT *)0 ) fputs( "{", OutFP );
wxI = 0;
if ( (exI & IO_LITONLY) == 0 || litP == (LIT *)0 ) {
switch( typeI ) {
default: sP = "?"; break;
case IO_INT: sP = "INT"; break;
case IO_BIT: sP = "BIT"; break;
case IO_FLT: sP = "REAL"; break;
}
fputs( sP, OutFP );
wxI = 1;
}
if ( litP != (LIT *)0 ) {
sP = (typeI == IO_BIT? "|":",");
for( ; litP->LNameCP != (char *)0; litP++ ) {
if ( wxI ) fputs( sP, OutFP );
wxI++;
fputs( litP->LNameCP, OutFP );
}
fputs( "}", OutFP );
}
}
if ( (exI & IO_OPT) != 0 ) fputs( "]", OutFP );
return( 0 );
}
lIPI = IPI;
if ( IPI != 0 && ctrI > 1 ) {
lIPI = 0;
fputs( ",\"", OutFP );
ConvertedL = 0;
}
if ( IPI >= 0 && ctrI > 1 ) {
/* --- Omit trailing items in an array which migh be zero --- */
typeI = 0;
switch( (inP->IInFuncC & IO_MASK) ) {
case IO_INT:
case IO_BIT:
switch( inP->ISizeI & 0xff ) {
case sizeof(char): typeI = 1; break;
case sizeof(short): typeI = 2; break;
case sizeof(long): typeI = 3; break;
}
break;
case IO_FLT:
if ( (inP->ISizeI & 0xff) == sizeof(float) )
typeI = 4;
else typeI = 5;
break;
}
exI = 0;
if ( typeI != 0 ) {
for( wxI = 0; wxI < ctrI; wxI++ ) {
switch( typeI ) {
case 1: if ( *p.cP++ != 0 ) exI = wxI; break;
case 2: if ( *p.sP++ != 0 ) exI = wxI; break;
case 3: if ( *p.lP++ != 0 ) exI = wxI; break;
case 4: if ( *p.fP++ != 0. ) exI = wxI; break;
case 5: if ( *p.dP++ != 0. ) exI = wxI; break;
}
}
exI++;
if ( ctrI > exI && IPI > 0 )
exI++;
ctrI = exI; /* re-set end point */
}
p.cP = inP->IValP; /* restore pointer */
}
for( ; --ctrI >= 0; ) {
wxI = 0;
switch( (ValTypeI = inP->IInFuncC & IO_MASK) ) {
case IO_NAK: case IO_LST: default:
break;
case IO_BIT:
case IO_INT:
switch( (inP->ISizeI & 0xff) ) {
case sizeof(char):
UsgnL = 0x000000ffL; SBitL = 0x00000080L;
vL = *p.cP++; break;
case sizeof(short):
UsgnL = 0x0000ffffL; SBitL = 0x00008000L;
vL = *p.sP++; break;
case sizeof(long):
UsgnL = 0xffffffffL; SBitL = 0x00000000L;
vL = *p.lP++; break;
default:
UsgnL = 0xffffffffL; SBitL = 0x00000000L;
vL = *p.iP++; break;
}
if ( inP->IOutFuncC == FMT_INTS ) {
if ( (vL & SBitL) != 0 ) vL |= ~UsgnL;
} else {
vL &= UsgnL;
}
/* --- See if it is in a literal table & use literal --- */
if ( ConvertedL ) fputs( ",", OutFP );
ConvertedL++;
if ( vL != 0 && ValTypeI == IO_BIT &&
(litP = inP->ILitTabP) != (LIT *)0 ) {
/* --- Translated an "or'd" bit-field --- */
if ( lIPI ) fputs( "\"", OutFP );
PrintBitI( vL, inP, OutFP );
if ( lIPI ) fputs( "\"", OutFP );
break;
}
if ( (litP = inP->ILitTabP) != (LIT *)0 ) {
vD = vL; /* map to double for compare */
wxI = 0; /* flag for "translated" */
for( ; litP->LNameCP != (char *)0; litP++ ) {
if ( vD == litP->LValueD ) {
wxI++;
if ( lIPI ) fputs( "\"", OutFP );
fputs( litP->LNameCP, OutFP );
if ( lIPI ) fputs( "\"", OutFP );
break;
}
}
if ( wxI ) break;
}
fprintf( OutFP, vL==0?"0":FmtA[inP->IOutFuncC], vL );
break;
case IO_FLT:
if ( (inP->ISizeI & 0xff) == sizeof(float) ) {
vD = *p.fP++;
} else {
vD = *p.dP++;
}
if ( ConvertedL ) fputs( ",", OutFP );
ConvertedL++;
if ( (litP = inP->ILitTabP) != (LIT *)0 ) {
wxI = 0;
for( ; litP->LNameCP != (char *)0; litP++ ) {
if ( vD == litP->LValueD ) {
wxI++;
if ( lIPI ) fputs( "\"", OutFP );
fputs( litP->LNameCP, OutFP );
if ( lIPI ) fputs( "\"", OutFP );
break;
}
}
if ( wxI ) break;
}
fprintf( OutFP, vD==0.0?"0":FmtA[inP->IOutFuncC], vD );
break;
case IO_STR:
wxI = 1;
goto StrCom;
case IO_FNM:
case IO_FLD:
case IO_DTE:
if ( lIPI ) wxI = 1;
StrCom:
if ( ConvertedL ) fputs( ",", OutFP );
if ( wxI ) fputs( "\"", OutFP );
fputs( p.cP, OutFP );
if ( wxI ) fputs( "\"", OutFP );
ConvertedL++;
goto Done; /* --- lists of strings not allowed --- */
}
}
if ( IPI != 0 && lIPI == 0 )
fputs( "\"", OutFP );
Done:
#ifdef TESTCMD
fflush( OutFP );
#endif
return( 0 );
}
/* */
/************************************************************************
* *
* PrintLstI() - Print out data values in a list *
* *
************************************************************************
inP->IValP has pointer to list of input items.
Last item has a null data pointer
*/
LOCAL int PrintLstI( inP, OutFP, IPI ) /* print out a list of values */
INPUT *inP; /* input list pointer */
FILE *OutFP; /* output file pointer */
int IPI; /* =1, import format */
{
INPUT *ainP; /* alternate input list */
char *wsP; /* work character pointer */
int rcI; /* local return code */
if ( inP == (INPUT *)0 || (ainP = (INPUT *)inP->IValP) == (INPUT *)0 )
return( -1 ); /* bad call */
if ( OutFP == (FILE *)0 ) OutFP = stdout;
if ( IPI>0 ) {
fputs( ",\"", OutFP );
ConvertedL = 0;
}
for( ; ainP->IValP != (char *)0; ainP++ ) {
switch( (ainP->IInFuncC & IO_MASK) ) {
case IO_NAK: default: break;
case IO_LST:
PrintLstI( ainP, OutFP, IPI<=0?IPI:0 ); break;
case IO_BIT:
case IO_INT: case IO_FLT:
case IO_STR: case IO_FNM: case IO_DTE: case IO_FLD:
PrintValI( ainP, OutFP, IPI<=0?IPI:0 ); break;
}
}
if ( IPI>0 )
fputs( "\"", OutFP );
#ifdef TESTCMD
fflush( OutFP );
#endif
return( 0 );
}
/* */
/************************************************************************
* *
* PrintTableI() - Print out data values in table *
* *
************************************************************************
IPI Modes:
-1, syntax structure
0, variables for display
1, variables for import
*/
LOCAL int PrintTableItemI( cmdP, OutFP, prefixCP, IPI ) /* print out table item */
CMD *cmdP; /* command table */
FILE *OutFP; /* output file pointer */
char *prefixCP; /* prefix for each line */
int IPI; /* =1, import format flag */
{
INPUT *inP; /* input pointer */
long fposL; /* file position */
long msgL; /* message id */
char *msgP; /* message pointer */
if ( OutFP == (FILE *)0 )
OutFP = stdout;
if ( cmdP->CNameCP != (char *)0 ) {
inP = &cmdP->CInS; /* input block */
if ( IPI >= 0 &&
( (cmdP->CActRtnP && (inP->IInFuncC & IO_DSP) == 0)
|| (inP->IInFuncC & IO_MASK) == IO_NAK) )
return( 0 ); /* skip commands */
fposL = ftell( OutFP ); /* save file position */
if ( IPI <= 0 && prefixCP != (char *)0 && *prefixCP != 0 )
fprintf( OutFP, "%s ", prefixCP );
fprintf( OutFP, IPI>0?"\"%s\"":"%-20s ", cmdP->CNameCP );
ConvertedL = IPI>0?1:0;
switch( (inP->IInFuncC & IO_MASK) ) {
case IO_NAK: default: /* should not happen */
break;
case IO_BIT:
case IO_INT: case IO_FLT:
case IO_STR: case IO_FNM: case IO_DTE: case IO_FLD:
PrintValI( inP, OutFP, IPI ); break;
case IO_LST:
PrintLstI( inP, OutFP, IPI ); break;
}
if ( (msgP = cmdP->CHelpCP) != (char *)0 ) {
fposL = ftell( OutFP ) - fposL;
if ( IPI <= 0 && fposL > 0 ) {
fposL = (fposL & (-8));
while( fposL < 40 ) {
fputs( "\t", OutFP );
fposL += 8;
}
}
fprintf( OutFP, IPI>0?",\"!%s\"":"\t!%s", msgP );
}
fputs( "\n", OutFP );
#ifdef TESTCMD
fflush( OutFP );
#endif
}
return( 0 );
}
int PrintTableI( cmdP, OutFP, prefixCP, IPI ) /* print out table */
CMD *cmdP; /* command table */
FILE *OutFP; /* output file pointer */
char *prefixCP; /* prefix for each line */
int IPI; /* =1, import format flag */
{
INPUT *inP; /* input pointer */
long fposL; /* file position */
for(; cmdP->CNameCP != (char *)0; cmdP++ )
PrintTableItemI( cmdP, OutFP, prefixCP, IPI ); /* print out table item */
return( 0 );
}
/* */
/************************************************************************
* *
* main() - Test Routine for Command Line Parser *
* *
************************************************************************
*/
#ifdef TESTCMD
double Tdouble = {0};
float Tfloat = {0};
long Tlong = {0};
short Tshort = {0};
char Tchar = {0};
int Tbool = {0};
char Tstr[] = {"Test String for I/O"};
char Tfil[] = {"filenamegoeshere"};
char Tfld[] = {"field.label[offset]"};
char TDate[] = {"mm/dd/yy"};
int Bit1=0, Bit2=0;
short Tarray[5] = {0,0,0,0,0};
LIT YesNo[] = {
{ "true", 1 }, { "yes", 1 }, { "on", 1 },
{ "false", 0 }, { "no", 0 }, { "off", 0 },
{ 0, 0 }
};
/* --- Input List to get several objects --- */
short L1I, L2I, L3I;
long L4I;
INPUT inl[] = {
IVAL(L1I, IO_INT, FMT_INTS, &YesNo[0]),
IVAL(L2I, IO_INT|IO_OPT, FMT_INTS, &YesNo[0]),
IVAL(L3I, IO_INT|IO_OPT, FMT_INTS, &YesNo[0]),
IVAL(L4I, IO_INT, FMT_INTS, &YesNo[0]),
INUL
};
int actI = {0};
int ActionRtne( cmdP, cvL, ErrFP )
CMD *cmdP; /* command pointer associated with me */
long cvL; /* count routine */
FILE *ErrFP; /* error output file */
{
fprintf( stdout, "actI = %d, Converted %ld items\n", actI, cvL );
fflush( stdout );
return( 0 );
}
int QuitI = {0};
int QuitRtne( cmdP, cvL, ErrFP ) /* quit command */
CMD *cmdP; /* command pointer associated with quit */
long cvL; /* # of conversions */
FILE *ErrFP; /* error output file */
{ QuitI = 1; return( 0 ); } /* set quit flag */
LIT Bits[] = {
{ "b1", 1 }, { "b2", 2 }, { "b3", 4 }, { "b4", 8 }, {0} };
CMD cmds[] = {
{ "quit", "quit help", QuitRtne, INUL },
{ "list", "list help", 0, ILIST( inl, 0 ) },
{ "act", "act help", ActionRtne, IVAL(actI,IO_INT|IO_OPT,FMT_INTS,0) },
{ "actdisp", "act help", ActionRtne,IVAL(actI,IO_INT|IO_OPT|IO_DSP,FMT_INTS,0)},
{ "tdouble", "double help", 0, IVAL(Tdouble,IO_FLT,FMT_FLT2,0) },
{ "tfloat", "float help", 0, IVAL(Tfloat, IO_FLT,FMT_FLT3,0) },
{ "tlong", "long help", 0, IVAL(Tlong, IO_INT,FMT_INTS,0) },
{ "tshort", "short help", 0, IVAL(Tshort, IO_INT,FMT_INTU,0) },
{ "tchar", "char help", 0, IVAL(Tchar, IO_INT,FMT_HEXU,0) },
{ "tbool", "bool help",0,IVAL(Tbool,IO_INT|IO_LITONLY,FMT_OCTU,&YesNo[0]) },
{ "tstr", "string help", 0, ISTR(Tstr, IO_STR) },
{ "tfil", "file help", 0, ISTR(Tfil, IO_FNM) },
{ "tdte", "date help", 0, ISTR(TDate, IO_DTE) },
{ "tfld", "field help", 0, ISTR(Tfld, IO_FLD) },
{ "tarray", "array help", 0, IVALA(Tarray,IO_INT|IO_OPT,FMT_INTS,0) },
{ "bit1", "bit-1 help", 0, IVAL(Bit1, IO_BIT|IO_LITONLY,FMT_INTS, &Bits[0]) },
{ "bit2", "bit-2 help", 0, IVAL(Bit2, IO_BIT,FMT_INTS, &Bits[0]) },
{ 0, 0, 0 }
};
int MsgER( buf )
char *buf; /* message buffer */
{
fputs( buf, stderr );
fputs( buf, stdout );
fflush( stdout );
return( -1 );
}
main(ac,av)
int ac; /* arg counter */
char *av[]; /* arg pointer */
{
int rc; /* return code */
char *sp; /* string pointer */
char *wsp; /* work string pointer */
char buf[80]; /* work buffer */
PrintTableI( &cmds[0], stdout, (char *)0, 0 );
PrintTableI( &cmds[0], stdout, (char *)0, 1 );
for( QuitI = 0; QuitI == 0 ;) {
fputs( "Enter Line>", stdout );
fflush( stdout );
sp = fgets( buf, sizeof(buf), stdin );
wsp = sp;
rc = ParseLineI( &wsp, &cmds[0], stdout, 1 ); /* syntax check */
if ( rc == 0 ) {
rc = ParseLineI( &sp, &cmds[0], stdout, 0 );
fprintf( stdout, "RC=%d\n", rc );
PrintTableI( &cmds[0], stdout, (char *)0, 0 );
}
}
exit( 0 );
}
#endif /* TESTCMD */